﻿using System;
using System.Collections.Generic;
using Epitech.Krisk.Xna.ScreenManagerLib.ScreenManager;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Epitech.Krisk.Xna.ScreenManagerLib.Widget
{
    public class LayoutEntry
    {
        /// <summary>
        /// Output of the layout at the begining or the ending of the list entry
        /// </summary>
        public enum LayoutOutput
        {
            /// <summary>
            /// Leave from the begin.
            /// </summary>
            Begin,
            /// <summary>
            /// Leave from the end.
            /// </summary>
            End,
            /// <summary>
            /// No leave.
            /// </summary>
            None
        };

        public enum TextAlignement
        {
            Right,
            Center,
            Left
        };

        List<MenuEntry> entries = new List<MenuEntry>();
        bool isSelect = false;

        public virtual void AddEntry(MenuEntry entry)
        {
            entry.Parent = this;
            MenuEntries.Add(entry);
            entry.ParentLayout = this;
        }

        public bool Active { get; set; }
        public List<MenuEntry> MenuEntries
        {
            get { return entries; }
        }

        public TextAlignement Alignement { get; set; }

        private int selectedEntry = -2;

        public int SelectedIndex
        {
            get { return selectedEntry; }
            set { selectedEntry = value; }
        }
        private Vector2 position = Vector2.Zero;

        public Vector2 Position
        {
            get { return position; }
            set { position = value; }
        }

        /// <summary>
        /// Contructor.
        /// Initializes a new instance of the <see cref="LayoutEntry"/> class.
        /// </summary>
        /// <param name="pos">The pos.</param>
        public LayoutEntry(Vector2 pos)
        {
            position = pos;
            Alignement = TextAlignement.Center;
            LineSpacing = 0.0f;
            Active = true;
        }

        /// <summary>
        /// Loads the content.
        /// </summary>
        /// <param name="currentScreen">The current screen.</param>
        public virtual void LoadContent(MenuScreen currentScreen)
        {
            foreach (var entry in entries)
            {
                entry.LoadContent(currentScreen);
            }
        }

        public virtual void UnloadContent()
        {
            foreach (var entry in entries)
            {
                entry.UnloadContent();
            }
        }

        public void ResetSelect(LayoutOutput left)
        {
            isSelect = true;
            if (left == LayoutOutput.Begin)
                selectedEntry = entries.Count - 1;
            else if (left == LayoutOutput.End)
                selectedEntry = 0;
        }

        /// <summary>
        /// Change selected entry in the Layout.
        /// </summary>
        /// <param name="currentScreen"></param>
        /// <param name="input">The input.</param>
        /// <param name="before"></param>
        public virtual LayoutOutput HandleInput(GameScreen currentScreen, InputState input, LayoutOutput before = LayoutOutput.None)
        {
            LayoutOutput leave = LayoutOutput.None;
            foreach (MenuEntry entry in MenuEntries)
            {
                entry.HandleInput(currentScreen, input);
            }

            if (Active)
            {
                isSelect = true;
                if (selectedEntry == -2)
                    selectedEntry = 0;
                if (before == LayoutOutput.Begin)
                    selectedEntry = entries.Count - 1;
                else if (before == LayoutOutput.End)
                    selectedEntry = 0;

                // Move to the previous menu entry?
                if (input.IsMenuUp(currentScreen.ControllingPlayer))
                {
                    selectedEntry--;

                    if (selectedEntry < 0)
                    {
                        leave = LayoutOutput.Begin;
                        isSelect = false;
                    }
                }

                // Move to the next menu entry?
                if (input.IsMenuDown(currentScreen.ControllingPlayer))
                {
                    selectedEntry++;

                    if (selectedEntry >= entries.Count)
                    {
                        leave = LayoutOutput.End;
                        isSelect = false;
                    }
                }
            }
            return leave;
        }

        public float LineSpacing { get; set; }

        public MenuEntry SelectedEntry
        {
            get { return this.entries[selectedEntry]; }
        }

        /// <summary>
        /// Updates the entry location.
        /// </summary>
        /// <param name="currentScreen">The current screen.</param>
        public virtual void UpdateEntryLocation(GameScreen currentScreen)
        {
            float transitionOffset = (float)Math.Pow(currentScreen.TransitionPosition, 2);

            Vector2 entryPosition = new Vector2(0f, this.position.Y);

            // update each menu entry's location in turn
            for (int i = 0; i < entries.Count; i++)
            {
                MenuEntry menuEntry = entries[i];

                // each entry is to be centered horizontally
                if (Alignement == TextAlignement.Center)
                    entryPosition.X = this.position.X - menuEntry.GetWidth(currentScreen) / 2;
                else if (Alignement == TextAlignement.Right)
                    entryPosition.X = this.position.X - menuEntry.GetWidth(currentScreen);
                else if (Alignement == TextAlignement.Left)
                    entryPosition.X = this.position.X;

                if (currentScreen.ScreenState == ScreenState.TransitionOn)
                    entryPosition.X -= transitionOffset * 256;
                else
                    entryPosition.X += transitionOffset * 512;

                // set the entry's position
                menuEntry.Position = entryPosition;

                // move down for the next entry the size of this entry
                if (LineSpacing == 0.0f)
                    entryPosition.Y += menuEntry.GetHeight(currentScreen);
                else
                    entryPosition.Y += LineSpacing;
            }
        }

        /// <summary>
        /// Update Layout
        /// </summary>
        /// <param name="gameTime">The game time.</param>
        /// <param name="currentScreen">The current screen.</param>
        /// <param name="otherScreenHasFocus">if set to <c>true</c> [other screen has focus].</param>
        /// <param name="coveredByOtherScreen">if set to <c>true</c> [covered by other screen].</param>
        public virtual void Update(GameTime gameTime, GameScreen currentScreen, bool otherScreenHasFocus, bool coveredByOtherScreen)
        {
            // Update each nested MenuEntry object.
            for (int i = 0; i < entries.Count; i++)
            {
                bool isSelected = currentScreen.IsActive && (i == selectedEntry);

                entries[i].Update(currentScreen, isSelected, gameTime);
            }
        }

        public virtual void Draw(GameTime gameTime, GameScreen currentScreen)
        {
            GraphicsDevice graphics = currentScreen.ScreenManager.GraphicsDevice;
            SpriteBatch spriteBatch = currentScreen.ScreenManager.SpriteBatch;
            SpriteFont font = currentScreen.ScreenManager.Font;

            // Draw each menu entry in turn.
            for (int i = 0; i < entries.Count; i++)
            {
                MenuEntry menuEntry = entries[i];

                bool isSelected = currentScreen.IsActive && (i == selectedEntry) && this.isSelect;

                menuEntry.Draw(currentScreen, isSelected, gameTime);
            }
        }
    }
}
